package com.chenyao.bookstore.dataprovider.impl;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import com.chenyao.bookstore.dataprovider.processor.IResultProcessor;
import com.chenyao.bookstore.util.Constants;

public abstract class BaseDataProvider<K extends Serializable, V extends Serializable> {

	protected IResultProcessor<V> resultProcessor;

	public BaseDataProvider() {
		this.initResultProcessor();
	}

	/**
	 * Execute a select SQL statement.
	 * 
	 * @author YongXia.
	 * 
	 * @since jdk1.6
	 * @version 1.0
	 * 
	 * @param sql
	 * @param parameters
	 * @return
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	protected List<V> find(final String sql, final Serializable[] parameters) throws SQLException,
			ClassNotFoundException {
		Connection conn = null;
		PreparedStatement pst = null;
		ResultSet results = null;
		List<V> list = null;
		try {
			conn = ConnectionFactory.getConnection();
			pst = conn.prepareCall(sql);
			if (null != parameters)
				this.setParameters(pst, parameters);
			results = pst.executeQuery();
			list = this.resultProcessor.process(results);
		} catch (SQLException e) {
			throw e;
		} finally {
			if (null != results) {
				results.close();
				results = null;
			}
			if (null != pst) {
				pst.close();
				pst = null;
			}
			if (conn != null) {
				conn.close();
				conn = null;
			}
		}
		return list;
	}

	/**
	 * Set a IResultProcessor<V> instance.
	 * 
	 * @author YongXia.
	 * 
	 * @since jdk1.6
	 * @version 1.0
	 * 
	 */
	protected abstract void initResultProcessor();

	/**
	 * Execute the save or update or delete SQL statement.
	 * 
	 * @author YongXia.
	 * 
	 * @since jdk1.6
	 * @version 1.0
	 * 
	 * @param sql
	 * @param parameters
	 * @return
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	protected int saveOrUpdateOrDelete(final String sql, final Serializable[] parameters) throws SQLException,
			ClassNotFoundException {
		Connection conn = null;
		PreparedStatement pst = null;
		int updateCount = Constants.ZERO;
		try {
			conn = ConnectionFactory.getConnection();
			pst = conn.prepareStatement(sql);
			if (null != parameters)
				this.setParameters(pst, parameters);
			updateCount = pst.executeUpdate();

		} catch (SQLException e) {
			throw e;
		} finally {
			if (null != pst) {
				pst.close();
				pst = null;
			}
			if (null != conn) {
				conn.close();
				conn = null;
			}
		}

		return updateCount;
	}

	/**
	 * Set the parameters for PreparedStatement instance.
	 * 
	 * @author YongXia.
	 * 
	 * @since jdk1.6
	 * @version 1.0
	 * 
	 * @param pst
	 * @param parameters
	 * @throws SQLException
	 */
	protected void setParameters(final PreparedStatement pst, final Serializable[] parameters) throws SQLException {
		if (null != parameters)
			for (int i = Constants.ZERO; i < parameters.length; ++i)
				pst.setObject(i + Constants.ONE, parameters[i]);
	}
}
